import { expect } from '@jest/globals';
import fse from 'fs-extra';
import path from 'path';

import { WorkerDataEts, WorkerDataTs } from '../../plugins/common-data';
import { buildOneHapAndCheckFile, commonJson5Operation, listZipEntries, readZipEntry } from '../../plugins/common-fun';
import {
  AbilityType,
  APIType,
  APIVersion,
  CaseLevel,
  IsEnable,
  LanguageType,
  ModuleTemplateType,
  RuntimeOSType,
  SDKType,
  SignType,
} from '../../plugins/project-builder/models/constants';
import { TestCaseBuilder } from '../../plugins/task-builder/task-case-builder';
import { ProjectBuildOption, TestCaseFun } from '../../plugins/task-builder/test-case';
import { TestTaskOption } from '../../plugins/task-builder/test-task-option';

const entryStageProjectBuilderOption: ProjectBuildOption = {
  template: {
    sdk: SDKType.Single,
    runtimeOS: RuntimeOSType.HarmonyOS,
    apiVersion: APIVersion.API10,
    apiType: APIType.STAGE,
    language: LanguageType.ArkTs,
    abilityType: AbilityType.Application,
    entryTemplateType: ModuleTemplateType.EmptyAbility
  }
};

const entryFaProjectBuilderOption: ProjectBuildOption = {
  template: {
    sdk: SDKType.Single,
    runtimeOS: RuntimeOSType.HarmonyOS,
    apiVersion: APIVersion.API10,
    apiType: APIType.FA,
    language: LanguageType.ArkTs,
    abilityType: AbilityType.Application,
    entryTemplateType: ModuleTemplateType.EmptyAbility
  }
};

const featureStageProjectBuilderOption: ProjectBuildOption = {
  template: {
    sdk: SDKType.Single,
    runtimeOS: RuntimeOSType.HarmonyOS,
    apiVersion: APIVersion.API10,
    apiType: APIType.STAGE,
    language: LanguageType.ArkTs,
    abilityType: AbilityType.Application,
    entryTemplateType: ModuleTemplateType.EmptyAbility
  },
  modulesOption: {
    [ModuleTemplateType.EmptyAbility]: 1
  }
};

const featureFaProjectBuilderOption: ProjectBuildOption = {
  template: {
    sdk: SDKType.Single,
    runtimeOS: RuntimeOSType.HarmonyOS,
    apiVersion: APIVersion.API10,
    apiType: APIType.FA,
    language: LanguageType.ArkTs,
    abilityType: AbilityType.Application,
    entryTemplateType: ModuleTemplateType.EmptyAbility
  },
  modulesOption: {
    [ModuleTemplateType.EmptyAbility]: 1
  }
};

const taskConfig: TestTaskOption = {
  caseLevel: CaseLevel.L1,
  sign: SignType.NoSign,
  ohpmInstall: IsEnable.Enable
};

const buildTestFun: (module: string) => TestCaseFun = (module: string) => async (project, taskConfig, record) => {
  // 1. 在模块中添加workers文件
  const moduleRootPath = project.getModule(module).moduleRootPath();
  await fse.ensureDir(path.resolve(moduleRootPath, 'src/main/ets/workers'));
  const WorkerData = project.option.apiType === APIType.STAGE ? WorkerDataEts : WorkerDataTs;
  const extendStr = project.option.apiType === APIType.STAGE ? 'ets' : 'ts';
  await fse.writeFile(path.resolve(moduleRootPath, `src/main/ets/workers/Worker.${extendStr}`), WorkerData);
  await fse.writeFile(path.resolve(moduleRootPath, `src/main/ets/workers/Worker1.${extendStr}`), WorkerData);

  // 2. 在模块的 build-profile.json5 文件中添加配置
  await commonJson5Operation(path.resolve(moduleRootPath, 'build-profile.json5'), async (json5: any) => {
    json5.buildOption.sourceOption = {
      'workers': [
        `./src/main/ets/workers/Worker.${extendStr}`,
        `./src/main/ets/workers/Worker1.${extendStr}`,
      ]
    };
  });

  // 3. 编译模块，并校验hap产物中是否有全量Worker文件
  await buildOneHapAndCheckFile(module)(project, taskConfig, record);
  const files = await fse.readdir(path.resolve(moduleRootPath, 'build/default/outputs/default'));
  const hapName = files.find(item => item.endsWith('.hap'));
  const hapPath = path.resolve(moduleRootPath, `build/default/outputs/default/${hapName}`);
  const workerStagePath = `${module}|${module}|1.0.0|src/main/ets/workers/Worker.ts`;
  const worker1StagePath = `${module}|${module}|1.0.0|src/main/ets/workers/Worker1.ts`;
  const workerFaPath = 'assets/js/workers/Worker.abc';
  const worker1FaPath = 'assets/js/workers/Worker1.abc';

  if (project.option.apiType === APIType.STAGE) {
    const sourceMapsContent = await readZipEntry(hapPath, 'ets/sourceMaps.map');
    const sourceMap = sourceMapsContent ? JSON.parse(sourceMapsContent!) : {};
    expect(workerStagePath in sourceMap && worker1StagePath in sourceMap).toBe(true);
  } else {
    const entries = (await listZipEntries(hapPath)).map(item => item[0]);
    expect(entries.includes(workerFaPath) && entries.includes(worker1FaPath)).toBe(true);
  }


  // 4. 修改模块的 build-profile.json5，重新编译，并校验hap产物中是否只有部分Worker文件
  await commonJson5Operation(path.resolve(moduleRootPath, 'build-profile.json5'), async (json5: any) => {
    json5.buildOption.sourceOption = {
      'workers': [
        `./src/main/ets/workers/Worker.${extendStr}`,
      ]
    };
  });
  await buildOneHapAndCheckFile(module)(project, taskConfig, record);

  if (project.option.apiType === APIType.STAGE) {
    const sourceMapsContent = await readZipEntry(hapPath, 'ets/sourceMaps.map');
    const sourceMap = sourceMapsContent ? JSON.parse(sourceMapsContent!) : {};
    expect(workerStagePath in sourceMap && !(worker1StagePath in sourceMap)).toBe(true);
  } else {
    const entries = (await listZipEntries(hapPath)).map(item => item[0]);
    expect(entries.includes(workerFaPath) && !entries.includes(worker1FaPath)).toBe(true);
  }

  // 5. 修改模块的 build-profile.json5，重新编译，并校验hap产物中是否有全量Worker文件
  await commonJson5Operation(path.resolve(moduleRootPath, 'build-profile.json5'), async (json5: any) => {
    json5.buildOption.sourceOption = {
      'workers': []
    };
  });
  await buildOneHapAndCheckFile(module)(project, taskConfig, record);

  // 当 build-profile.json5 不配置 worker时，stage打包全部携带， fa打包全部不携带
  if (project.option.apiType === APIType.STAGE) {
    const sourceMapsContent = await readZipEntry(hapPath, 'ets/sourceMaps.map');
    const sourceMap = sourceMapsContent ? JSON.parse(sourceMapsContent!) : {};
    expect(workerStagePath in sourceMap && worker1StagePath in sourceMap).toBe(true);
  } else {
    const entries = (await listZipEntries(hapPath)).map(item => item[0]);
    expect(!entries.includes(workerFaPath) && !entries.includes(worker1FaPath)).toBe(true);
  }
};

TestCaseBuilder.builder()
  .caseName('OPENLAB_AIDE_ZOS_Build_Workers_Project_Staget_Ets_HOS_api10_STAGE_001')
  .description('01.新模型stage-entry-ets构建workers-相对路径')
  .projectBuilderOption(entryStageProjectBuilderOption)
  .taskConfig(taskConfig)
  .testFun(buildTestFun('entry'))
  .load();

TestCaseBuilder.builder()
  .caseName('OPENLAB_AIDE_ZOS_Build_Workers_Project_Staget_Ets_HOS_api10_STAGE_006')
  .description('06.新模型stage-feature-ets构建workers-相对路径')
  .projectBuilderOption(featureStageProjectBuilderOption)
  .taskConfig(taskConfig)
  .testFun(buildTestFun('application'))
  .load();

TestCaseBuilder.builder()
  .caseName('OPENLAB_AIDE_ZOS_Build_Workers_Project_FA_API10_ArkTs_001')
  .description('01.老模型FA-entry-ets构建workers-相对路径')
  .projectBuilderOption(entryFaProjectBuilderOption)
  .taskConfig(taskConfig)
  .testFun(buildTestFun('entry'))
  .load();

TestCaseBuilder.builder()
  .caseName('OPENLAB_AIDE_ZOS_Build_Workers_Project_FA_API10_ArkTs_006')
  .description('06.老模型FA-feature-ets构建workers-相对路径')
  .projectBuilderOption(featureFaProjectBuilderOption)
  .taskConfig(taskConfig)
  .testFun(buildTestFun('application'))
  .load();
